#ifndef APPFORM_H
#define APPFORM_H

#include "base.h"
#include <qvariant.h> 
#include <qwidget.h> 
#include <qcanvas.h> 
#include <qpen.h> 
#include <qcolor.h>
#include <qsize.h> 
#include <qlistbox.h>
#include <qprogressbar.h> 
#include <qfocusdata.h> 
#include <qtabwidget.h> 
#include <qradiobutton.h> 
#include <qbuttongroup.h> 
#include <qtoolbutton.h>
#include <qpalette.h> 
#include <qdir.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <ctype.h>

#include<unistd.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<sys/ioctl.h>
#include<linux/soundcard.h>



#define BLOCK_WIDTH		26
#define BLOCK_HEIGHT		9
#define BLOCK_SPACE_X          1
#define BLOCK_SPACE_Y          1
#define BLOCK_X         	27
#define BLOCK_Y0         	30
#define BLOCK_Y         	(BLOCK_Y0 - (BLOCK_HEIGHT+BLOCK_SPACE_Y))
#define BLOCK_Y_MAX1		200   // 定义游戏活动区域下边界
#define BLOCK_Y_MAX2		120   // 当音符块下边沿碰到该水平线或在其下时, 
                                      // 该块被允许玩家琴键撞击
// 定义自动模式下音符块自动被击落的下边界
#define BLOCK_Y_MAX3		205
#define BLOCK_QUEUE_MAXSIZE  ((BLOCK_Y_MAX1-BLOCK_Y)/(BLOCK_HEIGHT+BLOCK_SPACE_Y)*7 + 5)
#define HINT_MAXTIME           500   // 琴键按下后系统提示持续最长时间ms         


#define START                	0
#define STOP  			1
#define PAUSE  			2
#define CONTINUE  		3
#define RUNNING  		4

#define NORMALMODE          	0
#define AUTOMODE  		1


class MyMusic
{
public:

    MyMusic() 
    {
        data = NULL;
        size = 0;
        syllable = 0;
        meter = 0;
        count = 0;
        step = 0;
        stepCount = 0;
        running = STOP;
        vaild = FALSE; 
        totalTime = 0;
        residualTime = 0;
        eslapedTime = 0;
        name = NULL;
        timeBase = 0;

        time.start();
    }

    ~MyMusic() 
    { 
       if (data != NULL)  delete data;     
       if (name != NULL)  delete name;    
    }

    void load(const char *filename);
    bool read();
    bool decode();
    bool decide();
    bool isOver() { return ( ((count >= size)&&(meter == 0)) ? TRUE : FALSE ); }
    unsigned char getMeter() {return meter;}
    void decMeter()  
    { 
       if (meter == 0) return;
       stepCount++;  
       if (stepCount >= step)
       {
          stepCount = 0;
          meter--;
       }
    }
    unsigned char getSyllable() {return syllable;}
    unsigned char getSyllable(int index) { return data[2*index];}
    unsigned char getMeter(int index) { return data[2*index+1];}

    bool isVaild() {return vaild;}
    unsigned char getStep() {return step;}
    unsigned char getCount() {return count;}
    unsigned long getTime() 
    {
       unsigned int sum = 0;
       for ( unsigned int i = 0; i < size/2; i++)
          sum += data[2*i+1];
       sum += (BLOCK_Y_MAX1 - BLOCK_Y)/(BLOCK_HEIGHT+BLOCK_SPACE_Y);

       totalTime = ((unsigned long)sum * step * speed + ((unsigned long)280*size/2));
       return totalTime;
    }
     


    unsigned long getEslapedTime() 
    { 
       if (running != RUNNING)
           eslapedTime =  timeBase;
       else 
           eslapedTime =  timeBase + time.elapsed (); 
       return eslapedTime;
    }


    void clearEslapedTime() 
    { 
       eslapedTime = 0;
       timeBase = 0;
    }

    void setSpeed(uint);
    uint getSpeed(void)  
    {  return speed;     }

    void setVolume(unsigned int volume)  
    {  this->volume = volume;     }

    uint getVolume(void)  
    {  return volume;     }


    char running;  	// 音乐执行状态 : STOP, PAUSE, RUNNING
    unsigned int size; 	// 音乐数据长度
    QTime time;
    unsigned long timeBase;

private:
    char *name;   	// 音乐文件名(含相对路径)
    char *data;  		// 音乐数据
    unsigned int count;  	// 音乐数据计数器
    unsigned char syllable; 	// 音节  
    unsigned char meter;   // 节拍  
    unsigned char step;    	// 每一个节拍分为多少步长
    unsigned char stepCount;   	// 步长计数器
    unsigned long totalTime;  	// 乐曲持续总时间
    unsigned long residualTime;  	// 乐曲剩余时间
    unsigned long eslapedTime;  	// 乐曲播放时间

    unsigned int speed;       	// 每一步长持续时间ms
                                // 1个节拍时间 = step * speed;
                                // 1个音符时间 = meter * step * speed;
    unsigned int volume;           // 乐曲音量

    bool vaild;			// 乐谱数据有效性

};


class MyQCanvas : public QCanvas
{ 
    Q_OBJECT
public:
    MyQCanvas ( int w, int h ) : QCanvas(w,h)
    {
    }

    virtual void drawBackground ( QPainter & painter, const QRect & clip )
    {
       QCanvas::drawBackground(painter,clip);
    }    

};



// 自定义音符块类

// 我们允许玩家在超过音符块的节拍时间做反应,
// 前提是该音符块还没消失在画面上, 这样做是为了适应更多玩家,
// 增加游戏的灵活性,可玩性; 也就是说只要音符块变成黄色, 超出
// 音符块meter节拍的时间外,也允许玩家有效击打
class MyQCanvasRectangle: public QCanvasRectangle
{
public:
    MyQCanvasRectangle ( const QRect & r, QCanvas * canvas, 
         unsigned char syllable, unsigned char meter, unsigned char step, unsigned char index) : QCanvasRectangle(r, canvas)
    { 
         this->syllable = syllable;
         this->meter = meter;
         this->step = step;
         this->index = index;
         stepCount = 0;
         hitEnable = FALSE;
    }

    void drawShape( QPainter & painter)
    {
	QCanvasRectangle::drawShape(painter);
    }

    // 确定玩家击打音符块后, 到下一个音符块允许被击打的时间间隔
    unsigned int residualStep()
    {
        if (meter == 0)  return 0;

        if (stepCount > step)
           return ((meter-1)*step);
        else
           return (meter*step - stepCount);
    }


    void incStepCount()
    { stepCount++;  }


    void setHitEnable()
    { hitEnable = TRUE;  }

    void clearHitEnable()
    { hitEnable = FALSE;  }

    bool getHitEnable()
    { return hitEnable;  }  

    unsigned char getSyllable() {return syllable; }


private: 
    unsigned char syllable; 	// 音符, 决定了当前音符块所在的音轨编号
    unsigned char meter;   // 节拍  
    unsigned char step;    // 每一个节拍分为多少步长
    unsigned char index;
    int stepCount; //记录了该块从允许被击打到消失, 持续了多少步的时间
    bool hitEnable; 
};



// 循环队列类, 队列元素为MyQCanvasRectangle型指针
class LoopQueue
{
public:
    LoopQueue( int size )
    {
        // 定义size个MyQCanvasRectangle型指针队列
        data  = new MyQCanvasRectangle *[size];
        _size = size;
        init();
    }


    ~LoopQueue()
    {
        clear();
    }


    // 队列初始化
    void init()
    {
        front = 0;
        rear = 0;
 
        for(int i = 0; i < _size; i++)
          data[i] = NULL;
    }

    // 队列初始化
    void clear()
    {

        for(int i = 0; i < _size; i++)
        {
            if (data[i] != NULL)
            {
               delete data[i];
               data[i] = NULL;
            }
        }
        delete data;
    }


    // 检查队列是否为空
    bool isEmpty()
    {
        return (front == rear) ? TRUE : FALSE;
    }


    // 队尾插入一个指针元素
    bool insertItem( MyQCanvasRectangle *item)
    {
       if ( (rear+1)%_size == front)  return FALSE; // 队列满,插入失败
     
       data[rear] = item;  // 队尾插入元素
       rear = (rear+1)%_size;  // 更新rear
       return TRUE;   
    }

    // 队首删除一个指针元素
    bool deleteItem()
    {
       if ( rear == front)  return FALSE; // 队列空,删除失败
       else 
       {  
          data[front] = NULL;
          front = (front+1)%_size;  // 删除队首元素
       }
       return TRUE;   
    }
   
    // Get 队列元素
    MyQCanvasRectangle *item(int index)
    {
       int i = (front+index)%_size;
       if (rear > front)
       {
          if ( i >= front && i < rear ) return data[i] ; 
       }
       else if (rear < front)
       {
          if ( i >= front || i < rear ) return data[i] ; 
       }
 
       return NULL ;   
    }


    MyQCanvasRectangle *first()
    {
       return data[front] ;   
    }

    // 队列元素最大个数
    int size()
    {
       return _size;   
    }

private:
    MyQCanvasRectangle **data;
    int _size;  // 队列元素最大个数
    int front, rear;
};



// 定义一个缓冲区类
class BUFFER
{
public:
    BUFFER()
    {
       size = 0;
       data = NULL;  
    }

    ~BUFFER()
    {
    }

public:
    uint size;
    char* data;
};

#define Audio_Device "/dev/dsp"

// 定义一个发音类
class MyAudio
{
public:
    MyAudio()
    {
        handle = -1;
        Sample_Rate = 44100;   //sampling rate
        Sample_Size = 16;  //there're two kinds of bits,8 bits and 16 bits

        // 加载7个标准发音
        loadSound();

        // 打开并初始化音频设备
        initAudioDevice();
    }

    ~MyAudio()
    {
        closeAudioDevice();
    }

    // 读文件数据
    bool readFile(const char *filename, char * &buf, uint &len)
    {
        int fd;
        struct stat stat_buf;

        // 打开文件 
        fd = open(filename, O_RDONLY);
        if (fd < 0) return FALSE;
    
        // 获取文件信息
        if (fstat(fd, &stat_buf))   // fstat()失败返回值为-1,成功则为0
        {
           close(fd);
           return FALSE;
        }

        if (!stat_buf.st_size)
        {
           close(fd);
           return FALSE;
        }

        // 分配数据缓冲区
        len = stat_buf.st_size;
        buf = new char[len+1];
        buf[len] = 0;

        // 读整个文件
        if (read(fd, buf, len) < 0)
        {
           close(fd);
           return FALSE;
        }

        // 关闭文件
        close(fd);

        return TRUE;
    }
    
    // 打开并初始化音频设备
    bool initAudioDevice()
    {
        int status;
        handle = open(Audio_Device,O_WRONLY);
        if (handle == -1)  return FALSE;

        status=ioctl(handle,SOUND_PCM_WRITE_RATE,&Sample_Rate);
        if(status == -1)
        {
           close(handle);
           handle = -1;
           return FALSE;
        }
        status=ioctl(handle,SOUND_PCM_WRITE_BITS,&Sample_Size);
        if(status == -1)
        {
           close(handle);
           handle = -1;
           return FALSE;
        }
        
        return  TRUE;
    }


    // 关闭音频设备
    void closeAudioDevice()
    {
       if (handle != -1)   close(handle);
    }

    // 加载7个琴键的发音,缓存之
    bool loadSound ()
    {
        readFile("/MG2440/wav/1.wav", buf[0].data, buf[0].size);
        readFile("/MG2440/wav/2.wav", buf[1].data, buf[1].size);
        readFile("/MG2440/wav/3.wav", buf[2].data, buf[2].size);
        readFile("/MG2440/wav/4.wav", buf[3].data, buf[3].size);
        readFile("/MG2440/wav/5.wav", buf[4].data, buf[4].size);
        readFile("/MG2440/wav/6.wav", buf[5].data, buf[5].size);
        readFile("/MG2440/wav/7.wav", buf[6].data, buf[6].size);
        return TRUE;
    }

    // 驱动发音
    bool playSound(BUFFER *buf)
    {
        if ((buf->data == NULL) || (buf->size == 0) || (handle == -1)) return FALSE;       

        if (-1 == write(handle,buf->data,buf->size))
        {
           return FALSE;
        }

        return TRUE;
    }
    
    // 依据琴键索引决定如何发音
    bool play_note(uint note)
    {
       // 控制发音
       if ((note >7) || (note == 0)) return FALSE; 
       if (-1 == playSound(&buf[note-1]))  return FALSE;
       return TRUE;
    }

private:
    int handle;
    uint Sample_Rate;
    uint Sample_Size;
    BUFFER buf[7];
};


class AppForm : public BaseForm
{ 
    Q_OBJECT
public:
    QString legalSingleKey;
    QWidget  *widgetMain;

    AppForm(QWidget* parent=0, const char* name=0, WFlags f=0);
    virtual ~AppForm();

    int  getSpeed ();
    void  setSpeed (int v);
    int  getVolume ();
    void  setVolume (int v);

    void buttonFlagInit();
    void gameControl();
    bool blockLife(MyQCanvasRectangle* block);
    bool blockEdgeCheck(MyQCanvasRectangle* block, int borderline);
    void blockHitEnableUpdate(MyQCanvasRectangle* block);
    bool AutoModeBlockHitCheck(MyQCanvasRectangle *block);
    void moveBlock(MyQCanvasRectangle* block); 
    MyQCanvasRectangle* addBlock(QRect* r); 

    QString Hotkey(QKeyEvent* k);
    void customHotkey (QWidget* w, QString str);
    void displayMusicTime();

    void paintEvent(QPaintEvent*);
    void keyPressEvent(QKeyEvent*);

    void scoreReport();
    
    bool readFile(char *filename, char * &buf, int &len);
    bool parseFile(char * string);
    bool loadConfigFile();
    bool saveConfigFile();
    void initConfig();
    void config();
    bool legalControlKey(QString);

    void ListDir( QDir *dir);

protected slots:
    virtual void buttonproc(unsigned char index);
    virtual void button1proc();
    virtual void button2proc();
    virtual void button3proc();
    virtual void button4proc();
    virtual void button5proc();
    virtual void button6proc();
    virtual void button7proc();
    virtual void decSpeed();
    virtual void decVolume();
    virtual void incSpeed();
    virtual void incVolume(); 
    virtual void languageChange(); 
    void timer1Proc();
    void timer2Proc();
    void timer3Proc();
    void timer4Proc();

    void currentChangedFileItem();
    void selectFileItem();
    void startGame();
    void pauseGame();
    void changeMode(int);
    void loadMode( );

private:

    MyQCanvas* canvas;
    QRect* rects[7];
    QPopupMenu* options;
    QPixmap* pixImg1; 
    QRect* canvasArea;
    QTimer* timer1;
    QTimer* timer2;
    QTimer* timer3;   // 1秒周期性定时显示歌曲播放剩余时间
    QTimer* timer4;   // 超时后执行scoreReport(),统计显示成绩
    QPainter* painter;
    MyMusic* music;
    FILE* fp;
    char buttonFlag[7];

    LoopQueue *queue;

    int hitHorizontalLine;

    unsigned int reportFailCount;
    unsigned int reportGoodCount;  
    unsigned int reportMissCount; 

       
    unsigned int speedValue;  // 记录当前进度条上的乐曲速度参数
    unsigned int volumeValue; // 记录当前进度条上的乐曲音量参数   
    QString soundkey;  // 记录了当前的7个琴键的字符串
    QString startkey;   // 记录了控制游戏开始/停止的键
    QString pausekey;  // 记录了控制游戏暂停/继续的键
 
    QDir *musicDir;
    QWidget* Advance;
    QButtonGroup* ModeButtonGroup;
    QRadioButton* NormalModeButton;
    QRadioButton* AutoModeButton;      
    unsigned char gameMode; 

    QGroupBox* GroupBox4;
    QLabel* TextLabel3;
    QLabel* TextLabel2;
    QToolButton* ToolButton1;
    QToolButton* ToolButton3;
    QProgressBar* ProgressBar2;
    QToolButton* ToolButton4;
    QProgressBar* ProgressBar1;
    QToolButton* ToolButton2;

    MyAudio  audio;

    QPalette  palette1;
    QPalette  palette2;
    QPalette  palette3;

    bool paintFlag;

};





#endif // APPFORM_H
